import React from 'react';
import PropTypes from 'prop-types';
import DnD from './dnd';
import {
    defaultDragItem,
    defaultExpandDown,
    defaultExpandUp,
    defaultRemove,
    defaultStaticItem
} from './components/default';

// 最小刻度
const fixOffset = (offset, unit) => Math.round(offset / unit) * unit;

const nextRangeHandlerMap = {
    move: (range, offset) => [range[0] + offset, range[1] + offset],
    expandUp: (range, offset) => [range[0] + offset, range[1]],
    expandDown: (range, offset) => [range[0], range[1] + offset]
};

const RangeDnD = ({
    height,
    rowsNum = 24,
    rowHeight = 32, // 只能为minUnit倍数
    minUnit = 1,
    defaultRangeList = [],
    staticRangeList = [],
    customRemove = false,
    customItems = [], // {id, range, render}
    onRangeAdd,
    onRangeDrag,
    onRangeRemove,
    onRangeChange,
    renderDragItem = defaultDragItem,
    renderExpandUp = defaultExpandUp,
    renderExpandDown = defaultExpandDown,
    renderRemove = defaultRemove,
    renderStaticItem = defaultStaticItem
}) => {
    const [rangeList, setRangeList] = React.useState(defaultRangeList);

    const rows = [...Array(rowsNum).keys()];

    const handleChange = (index, distance, type) => {
        setRangeList(
            rangeList.map((item, itemIndex) => {
                if (index === itemIndex) {
                    const nextData = {
                        ...item,
                        range: nextRangeHandlerMap[type](item.range, fixOffset(distance, minUnit))
                    };
                    if (onRangeDrag) onRangeDrag(nextData, type);
                    return nextData;
                }
                return item;
            })
        );
    };

    const getFillItemStyle = (range, extra = {}) => {
        if (!range) return {};
        const [start, end] = range;
        return {
            position: 'absolute',
            width: '100%',
            top: start,
            height: end - start,
            border: 0,
            ...extra
        };
    };

    const handleAddRange = rowIndex => {
        const nextId = (rangeList.length ? Math.max(...rangeList.map(item => item.id)) : 0) + 1;
        let extraData = {};
        let range = [rowIndex * rowHeight, (rowIndex + 2) * rowHeight];
        if (rowIndex % 2 === 1) {
            range = [(rowIndex - 1) * rowHeight, (rowIndex + 1) * rowHeight];
        }
        const baseData = {
            id: nextId,
            range
        };
        if (onRangeAdd) extraData = onRangeAdd(baseData) ?? {};
        setRangeList([
            ...rangeList,
            {
                ...baseData,
                ...extraData
            }
        ]);
    };

    const handleRemoveRange = id => {
        if (onRangeRemove) onRangeRemove(rangeList.find(item => item.id === id));
        setRangeList(rangeList.filter(item => item.id !== id));
    };

    const dndRef = React.useRef();
    const contextRef = React.useRef();

    React.useEffect(() => {
        dndRef.current = new DnD();
        dndRef.current.initialize({
            minUnit, // 最小单位
            context: contextRef.current
        });
        return () => {
            dndRef.current.destroy();
        };
    }, []);

    // handleChange中rangeList需要更新
    React.useEffect(() => {
        dndRef.current.setOption({
            onComplete: handleChange
        });
        if (onRangeChange) onRangeChange(rangeList);
    }, [rangeList]);

    React.useEffect(() => {
        dndRef.current.resize();
    }, [height]);

    return (
        <div ref={contextRef}>
            <div data-range-dnd-scroll style={{ height: '100%', overflowY: 'auto' }}>
                <div style={{ position: 'relative' }} data-range-dnd-context>
                    {rows.map(rowIndex => (
                        <div
                            key={rowIndex}
                            style={{ height: rowHeight }}
                            onClick={e => {
                                e.preventDefault();
                                handleAddRange(rowIndex);
                            }}
                        />
                    ))}
                    {rangeList.map(item => (
                        <div key={item.id} data-range-dnd-item style={getFillItemStyle(item.range, { zIndex: 2 })}>
                            {renderDragItem(item)}
                            <div data-range-dnd-expand-up>{renderExpandUp(item)}</div>
                            <div data-range-dnd-expand-down>{renderExpandDown(item)}</div>
                            <div
                                data-range-dnd-delete
                                onClick={e => {
                                    e.preventDefault();
                                    if (!customRemove) {
                                        handleRemoveRange(item.id);
                                    }
                                }}
                            >
                                {renderRemove(customRemove ? () => handleRemoveRange(item.id) : '')}
                            </div>
                        </div>
                    ))}
                    {staticRangeList.map(item => (
                        <div key={item.id} style={getFillItemStyle(item.range, { zIndex: 1 })}>
                            {renderStaticItem(item)}
                        </div>
                    ))}
                    {customItems.map(item => (
                        <div key={item.id} style={getFillItemStyle(item.range)}>
                            {item.render}
                        </div>
                    ))}
                </div>
            </div>
        </div>
    );
};

RangeDnD.prototypes = {
    height: PropTypes.number, // 容器高度，如果容器高度有动态变化，需要height传入进行reRender
    rowsNum: PropTypes.number, // 行数
    rowHeight: PropTypes.number, // 行高，需要为minUnit的倍数
    minUnit: PropTypes.number, // 最小位移单位
    defaultRangeList: PropTypes.array, // 默认数据
    staticRangeList: PropTypes.array, // 静态对比数据
    customItems: PropTypes.array, // 自定义数据,
    onRangeAdd: PropTypes.func, // 添加区间回调
    onRangeDrag: PropTypes.func, // 拖动区间回调
    onRangeRemove: PropTypes.func, // 移除区间回调
    onRangeChange: PropTypes.func, // 区间变更回调
    renderDragItem: PropTypes.element, // 自定义拖动项
    renderExpandUp: PropTypes.element, // 自定义向上延展按钮
    renderExpandDown: PropTypes.element, // 自定义向下延展按钮
    renderRemove: PropTypes.element, // 自定义移除按钮
    renderStaticItem: PropTypes.element // 自定义静态对比项
};

export default RangeDnD;
